package com.songlanyun.modules.gains.service.impl;

import cn.hutool.core.map.MapUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.songlanyun.common.enums.LockPrefixConstant;
import com.songlanyun.common.enums.ShopGainsConstant;
import com.songlanyun.common.exception.RRException;
import com.songlanyun.common.utils.custom.DateCustomUtils;
import com.songlanyun.common.validator.ValidatorUtils;
import com.songlanyun.modules.exception.ShopException;
import com.songlanyun.modules.gains.entity.ShopOrderGains;
import com.songlanyun.modules.shop.entity.ShopEntity;
import com.songlanyun.modules.shop.service.ShopService;
import org.apache.commons.lang.StringUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Date;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.songlanyun.common.utils.PageUtils;
import com.songlanyun.common.utils.Query;

import com.songlanyun.modules.gains.dao.ShopGainsBillDao;
import com.songlanyun.modules.gains.entity.ShopGainsBill;
import com.songlanyun.modules.gains.service.ShopGainsBillService;


@Service("shopGainsBillService")
public class ShopGainsBillServiceImpl extends ServiceImpl<ShopGainsBillDao, ShopGainsBill> implements ShopGainsBillService {

    @Autowired
    private ShopService shopService;

    @Autowired
    private RedissonClient redissonClient;

    @Override
    public ShopGainsBill create(ShopGainsBill entity) {
        ValidatorUtils.validateEntity(entity);
        this.baseMapper.insert(entity);
        return entity;
    }

    @Override
    public ShopGainsBill modify(ShopGainsBill entity) {
        ValidatorUtils.validateEntity(entity);
        this.baseMapper.updateById(entity);
        return entity;
    }

    @Override
    public void remove(Long id) {

    }

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        LambdaQueryWrapper<ShopGainsBill> query = new LambdaQueryWrapper<>();
        query.eq(ShopGainsBill::getShopId, MapUtil.getLong(params, "shop_id"));
        if (params.containsKey("bill_type")) {
            query.eq(MapUtil.getInt(params, "bill_type") != null, ShopGainsBill::getBillType, MapUtil.getInt(params, "bill_type"));
        }

        if (params.containsKey("inner_mode")) {
            query.eq(MapUtil.getInt(params, "inner_mode") != null, ShopGainsBill::getInnerMode, MapUtil.getInt(params, "inner_mode"));
        }

        if (params.containsKey("outer_mode")) {
            query.eq(MapUtil.getInt(params, "outer_mode") != null, ShopGainsBill::getOuterMode, MapUtil.getInt(params, "outer_mode"));
        }
        String code = MapUtil.getStr(params, "code");
        if (StringUtils.isNotBlank(code)) {
            query.like(ShopGainsBill::getCode, code);
        }

        if (params.containsKey("start_time")) {
            Date d = DateCustomUtils.stringToDateTime(MapUtil.getStr(params, "start_time"));
            if (d != null) {
                Long startTime = d.getTime();
                query.ge(ShopGainsBill::getCreateTimeMillis, startTime);
            }
        }
        if (params.containsKey("end_time")) {
            Date e = DateCustomUtils.stringToDateTime(MapUtil.getStr(params, "end_time"));
            if (e != null) {
                Long eTime = e.getTime();
                query.le(ShopGainsBill::getCreateTimeMillis, eTime);
            }
        }

        query.orderByDesc(ShopGainsBill::getCreateTimeMillis);
        IPage<ShopGainsBill> page = this.page(
                new Query<ShopGainsBill>().getPage(params),
                query
        );

        return new PageUtils(page);
    }

    /**
     * 增加所得入帐
     *
     * @param shopId
     * @param innerMode
     * @param billMoney
     * @param remark
     * @return
     */
    @Override
    public ShopGainsBill inBill(Long shopId, ShopGainsConstant.InnerMode innerMode, BigDecimal billMoney, String remark, String code) {
        ShopEntity shop = null;
        BigDecimal gainsAble = BigDecimal.ZERO;

        shop = shopService.loadByIdForLock(shopId, true);
        gainsAble = shop.getGainsAble();
        shop.addGains(billMoney);
        shopService.updateById(shop);

        ShopGainsBill shopGainsBill = new ShopGainsBill();
        shopGainsBill.setShopId(shopId);
        shopGainsBill.setBillType(ShopGainsConstant.BillType.INCOME);
        shopGainsBill.setCreateTimeMillis(System.currentTimeMillis());
        shopGainsBill.setEntryBefore(gainsAble);
        shopGainsBill.setEntryValue(billMoney);
        shopGainsBill.setEntryAfter(shop.getGainsAble());
        shopGainsBill.setInnerMode(innerMode);
        shopGainsBill.setOuterMode(ShopGainsConstant.OuterMode.EMPTY);
        shopGainsBill.setRemark(remark);
        shopGainsBill.setCode(code);
        this.create(shopGainsBill);

        return shopGainsBill;
    }

    /**
     * 减少商家所得入账
     *
     * @param shopId
     * @param outerMode
     * @param billMoney
     * @param remark
     * @return
     */
    @Override
    public ShopGainsBill outBill(Long shopId, ShopGainsConstant.OuterMode outerMode, BigDecimal billMoney, String remark, String code) {
        ShopEntity shop = null;
        BigDecimal gainsAble = BigDecimal.ZERO;

        shop = shopService.loadByIdForLock(shopId, true);
        //判断金额是否充足
        if (shop.getGainsAble().compareTo(billMoney) < 0) {//商家可提现所得是否到达上限
            throw new RRException(ShopException.SHOP_WITHDRAW_INSUFFICIENT_FUND);
        }
        gainsAble = shop.getGainsAble();
        shop.decGains(billMoney);
        shopService.updateById(shop);


        ShopGainsBill shopGainsBill = new ShopGainsBill();
        shopGainsBill.setShopId(shopId);
        shopGainsBill.setBillType(ShopGainsConstant.BillType.EXPENDITURE);
        shopGainsBill.setCreateTimeMillis(System.currentTimeMillis());
        shopGainsBill.setEntryBefore(gainsAble);
        shopGainsBill.setEntryValue(billMoney);
        shopGainsBill.setEntryAfter(shop.getGainsAble());
        shopGainsBill.setInnerMode(ShopGainsConstant.InnerMode.EMPTY);
        shopGainsBill.setOuterMode(outerMode);
        shopGainsBill.setRemark(remark);
        shopGainsBill.setCode(code);
        this.create(shopGainsBill);

        return shopGainsBill;
    }
}